#ifndef __CLOUD_SERVICE__
#define __CLOUD_SERVICE__

#include <thread>
#include <chrono>
#include "httplib.h"
#include "hot_manager.hpp"
#include "log_system/log_system.h"


cloud::HotManager hot_manager_g;

namespace cloud
{
#define SERVICE_LOGGER "service_logger"
    class Service
    {
    private:
        int _server_port;
        std::string _server_ip;
        std::string _download_prefix;
        httplib::Server _server;

    private:
        static std::string Time2Str(time_t time)
        {
            return std::string(std::ctime(&time));
        }

        static std::string GetETag(const BackupInfo& info)
        {
            return FileUtil(info._backup_path).FileName() 
                + "-" + std::to_string(info._file_size) 
                + "-" + std::to_string(info._mtime);
        }

    private:
        static void Upload(const httplib::Request& req, httplib::Response& rsp)
        {
            log_system::Logger::ptr logger = log_system::getLogger(SERVICE_LOGGER);
            logger->infoLog("接收upload请求");

            if(!req.has_file("file"))
            {
                logger->warnLog("upload请求,但未上传文件");
                rsp.status = 400;
                return;
            }
            const auto& file_form_data = req.get_file_value("file");
            std::string backup_path = Configuration::GetInstance()->GetBackupDir() + file_form_data.filename;

            
            FileUtil fu(backup_path);
            if(fu.SetContent(file_form_data.content))
            {
                logger->infoLog("将upload文件%s保存到%s",file_form_data.filename.c_str(),backup_path.c_str());
            }
            else
            {
                logger->errorLog("upload文件%s保存失败!",file_form_data.filename.c_str());
                rsp.status = 500;// 服务器内部错误，无法完成请求
                return;
            }

            BackupInfo info;
            BackupInfo::CreateNewBackupInfo(backup_path, &info);
            BackupInfoManager::GetInstance()->Insert(info);

            //对于新上传的文件，若存在同名的旧的压缩文件，以新文件为准。
            FileUtil invalid_file_fu(info._compress_path);
            if(invalid_file_fu.Exists())
            {
                logger->infoLog("删除upload文件%s的过期备份压缩包",file_form_data.filename.c_str());
                invalid_file_fu.Delete();
            }
        }

        static void ShowList(const httplib::Request& req, httplib::Response& rsp)
        {
            log_system::Logger::ptr logger = log_system::getLogger(SERVICE_LOGGER);
            logger->infoLog("接收showlist请求");

            // 1.获取文件备份信息
            std::vector<BackupInfo> array;
            BackupInfoManager::GetInstance()->GetAll(&array);

            // 2.根据所有备份信息，组织html文件数据
            std::stringstream ss;
            ss << R"(<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>List</title></head>)";
            ss << "<body><h1>Download</h1><table><tbody>";
            for(auto& info : array)
            {
                ss << "<tr>";
                ss << "<td><a href='" << info._download_url << "'>" << FileUtil(info._backup_path).FileName() << "</a></td>";
                ss << "<td align='right'>" << Time2Str(info._mtime) << "</td";
                ss << "<td align='right'>" << info._file_size / 1024 << "KB</td";
                ss << "</tr>";
            }
            ss << "</tbody></table></body></html>";
            logger->infoLog("构建响应页面");
            
            // 3.构建响应
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
        }

        static void Download(const httplib::Request& req, httplib::Response& rsp)
        {
            log_system::Logger::ptr logger = log_system::getLogger(SERVICE_LOGGER);
            logger->infoLog("接收download请求");

            // 1.根据资源路径获取文件备份信息
            BackupInfo info;
            if(!BackupInfoManager::GetInstance()->GetOneByUrl(req.path, &info))
            {
                logger->warnLog("download请求资源路径%s不存在",req.path.c_str());
                rsp.status = 404;
                return;
            }

            hot_manager_g.UncompressBeforeDownload(info);
            
            // 3.确定下载方式是从头下载还是续传下载
            bool is_range = false;
            std::string cur_etag = GetETag(info);
            if(req.has_header("If-Range") && cur_etag == req.get_header_value("If-Range"))
            {
                is_range = true;
                logger->infoLog("download请求%s为续传下载",req.path.c_str());
            }
            else
            {
                logger->infoLog("download请求%s为正常下载",req.path.c_str());
            }
        
            // 4.读取文件数据
            FileUtil fu(info._backup_path);
            //httplib会自动截取Range字段对应的区间的内容
            if(fu.GetContent(&rsp.body))
            {
                logger->infoLog("加载download请求资源路径%s文件%s成功",req.path.c_str(),info._backup_path.c_str());
            }
            else
            {
                logger->errorLog("加载download请求资源路径%s文件%s失败",req.path.c_str(),info._backup_path.c_str());
                rsp.status = 500;
                return;
            }

            // 5.设置响应头字段
            if(!is_range)
            {
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("ETag", cur_etag);
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 200;
            }
            else
            {
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("ETag", cur_etag);
                rsp.set_header("Content-Type", "application/octet-stream");

                //httplib会自动设置Content-Range字段
                rsp.status = 206;
            }
        }

    public:
        Service()
        {
            Configuration* conf = Configuration::GetInstance();
            _server_port = conf->GetServerPort();
            _server_ip = conf->GetServerIp();
            _download_prefix = conf->GetDownloadPrefix();

            std::unique_ptr<log_system::LoggerBuilder> glBuilder(new log_system::GlobalLoggerBuilder());
            glBuilder->buildLoggerName(SERVICE_LOGGER);
            glBuilder->buildLoggerType(log_system::LoggerType::LOGGER_ASYNC);
            glBuilder->buildSink<log_system::FileSink>("./log/service_logger.txt");

            glBuilder->build();
        }


        bool Run()
        {
            log_system::Logger::ptr logger = log_system::getLogger(SERVICE_LOGGER);

            // 处理上传请求
            _server.Post("/upload", Upload);

            // 处理展示请求
            _server.Get("/", ShowList);

            // 处理展示请求
            _server.Get("/list", ShowList);

            // 处理下载请求
            std::string download_url = _download_prefix + "(.*)";
            _server.Get(download_url, Download);

            logger->infoLog("启动热点管理模块");
            std::thread([](){
                hot_manager_g.RunCompressDetect();
            }).detach();

            if(!_server.listen(_server_ip, _server_port))
            {
                logger->fatalLog("服务器监听%s:%d失败!",_server_ip.c_str(),_server_port);
                
                return false;
            }
            logger->infoLog("服务器启动成功，监听%s:%d",_server_ip.c_str(),_server_port);

            return true;
        }
    };

}

#endif